﻿using Bio;
using Bio.IO.FastA;
using Candy.Infrastructure;
using Candy.Model;
using Candy.Web.Data;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using GalaSoft.MvvmLight.Threading;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.ServiceModel.DomainServices.Client;
using System.Windows;

namespace Candy.ViewModel
{
    public class FamiliesViewModel : CandyViewModelBase
    {
        private bool _isBusy;
        public bool IsBusy
        {
            get
            {
                return _isBusy;
            }
            set
            {
                _isBusy = value;
                RaisePropertyChanged("IsBusy");
                if (value)
                    base.ReportProgress();
                else
                    base.FinishProgress();
                Load.RaiseCanExecuteChanged();
            }
        }

        private ObservableCollection<FamilyEditViewModel> _families;
        public ObservableCollection<FamilyEditViewModel> Families
        {
            get
            {
                return _families;
            }
            set
            {
                _families = value;
                RaisePropertyChanged("Families");
            }
        }

        private ObservableCollection<FamilyDto> _familyList;
        public ObservableCollection<FamilyDto> FamilyList
        {
            get
            {
                return _familyList;
            }
            set
            {
                _familyList = value;
                RaisePropertyChanged("FamilyList");
            }
        }

        private FamilyEditViewModel _selectedFamily;
        public FamilyEditViewModel SelectedFamily
        {
            get
            {
                return _selectedFamily;
            }
            set
            {
                _selectedFamily = value;
                RaisePropertyChanged("SelectedFamily");
                MessengerInstance.Send<NotificationMessage<FamilyEditViewModel>>(new NotificationMessage<FamilyEditViewModel>(_selectedFamily, ViewModelMessageTypes.SelectFamily));
            }
        }



        IDataService _dataService;
        INavigationService _navigationService;
        public FamiliesViewModel(IDataService dataService, INavigationService navigationService)
        {
            _dataService = dataService;
            _navigationService = navigationService;
            if (IsInDesignMode)
            {
                Load.Execute(null);
            }

            _dataService.ProjectInitialized += _dataService_ProjectInitialized;
        }

        void _dataService_ProjectInitialized(object sender, EventArgs e)
        {
            _isLoaded = true;
            DispatcherHelper.CheckBeginInvokeOnUI(() =>
                {
                    FamilyList = new ObservableCollection<FamilyDto>(_dataService.Families.OrderBy(x => x.Name));

                    Families = new ObservableCollection<FamilyEditViewModel>();
                    var roots = from x in _dataService.Families
                                where x.ParentId.HasValue == false
                                orderby x.Name
                                select x;

                    foreach (var item in roots)
                    {
                        FamilyEditViewModel vm = new FamilyEditViewModel(_dataService, _navigationService, _dataService.Families, item);
                        _families.Add(vm);
                    }

                    SelectedFamily = _families.FirstOrDefault();
                    _dataService.Families.EntityAdded += Families_EntityAdded;
                    _dataService.Families.EntityRemoved += Families_EntityRemoved;
                });
        }

        void Families_EntityAdded(object sender, System.ServiceModel.DomainServices.Client.EntityCollectionChangedEventArgs<Web.Data.FamilyDto> e)
        {
            DispatcherHelper.CheckBeginInvokeOnUI(() =>
                {
                    FamilyList.Add(e.Entity);
                    if (e.Entity.ParentId.HasValue == false)
                        Families.Add(new FamilyEditViewModel(_dataService, _navigationService, _dataService.Families, e.Entity));
                });
        }

        void Families_EntityRemoved(object sender, EntityCollectionChangedEventArgs<FamilyDto> e)
        {
            DispatcherHelper.CheckBeginInvokeOnUI(() =>
               {
                   FamilyList.Remove(e.Entity);
                   if (e.Entity.ParentId.HasValue == false)
                   {
                       var vm = Families.SingleOrDefault(x => x.Entity == e.Entity);
                       Families.Remove(vm);
                   }
               });
        }



        private bool _isLoaded;
        private RelayCommand _load;
        public RelayCommand Load
        {
            get
            {
                return _load ?? (_load = new RelayCommand(ExecLoad, CanLoad));
            }
        }

        /// <summary>
        /// Checks whether the Load command is executable
        /// </summary>
        private bool CanLoad()
        {
            return !_isLoaded && !IsBusy;
        }

        /// <summary>
        /// Executes the Load command 
        /// </summary>
        private void ExecLoad()
        {

            //    IsBusy = true;



            //_dataService.LoadFamiliesAsync(op =>
            //    {
            //        IsBusy = false;
            //        if (op.HasError)
            //        {
            //            base.HandleDomainError(op, "Loading family hirachy failed.");
            //        }
            //        else
            //        {
            //            _isLoaded = true;
            //            Families = new ObservableCollection<FamilyEditViewModel>();
            //            var roots = from x in op.Entities
            //                        where x.ParentId.HasValue == false
            //                        select x;

            //            foreach (var item in op.Entities)
            //            {
            //                if (item.ParentId.HasValue)
            //                {

            //                }
            //                else
            //                {
            //                    FamilyEditViewModel vm = new FamilyEditViewModel(_dataService, _navigationService, _dataService.Families, item);
            //                    _families.Add(vm);
            //                }

            //            }



            //            _dataService.Families.EntityAdded += FamilyDtos_EntityAdded;
            //            _dataService.Families.EntityRemoved += FamilyDtos_EntityRemoved;
            //        }
            //    });
        }




        private RelayCommand<FamilyEditViewModel> _createFamily;
        public RelayCommand<FamilyEditViewModel> CreateFamily
        {
            get
            {
                return _createFamily ?? (_createFamily = new RelayCommand<FamilyEditViewModel>(ExecCreateFamily, CanCreateFamily));
            }
        }

        /// <summary>
        /// Checks whether the CreateFamily command is executable
        /// </summary>
        private bool CanCreateFamily(FamilyEditViewModel val)
        {
            return true;
        }

        /// <summary>
        /// Executes the CreateFamily command 
        /// </summary>
        /// <param name="parentFamily">The parent family</param>
        private void ExecCreateFamily(FamilyEditViewModel parentFamily)
        {
            var vm = new FamilyEditViewModel(_dataService, _navigationService, _dataService.Families, new Web.Data.FamilyDto() { Name = "NewFamily" });
            vm.Entity.ProjectId = _dataService.LoadedProject.Id;
            vm.Entity.Type = Web.Data.FamilyType.family;
            if (parentFamily != null)
                vm.Entity.ParentId = parentFamily.Entity.Id;
            vm.Edit.Execute(null);
            _navigationService.ShowFamilyEditor(vm);
        }




        private RelayCommand<FamilyEditViewModel> _editFamily;
        public RelayCommand<FamilyEditViewModel> EditFamily
        {
            get
            {
                return _editFamily ?? (_editFamily = new RelayCommand<FamilyEditViewModel>(ExecEditFamily, CanEditFamily));
            }
        }

        /// <summary>
        /// Checks whether the EditFamily command is executable
        /// </summary>
        private bool CanEditFamily(FamilyEditViewModel val)
        {
            return val != null;
        }

        /// <summary>
        /// Executes the EditFamily command 
        /// </summary>
        private void ExecEditFamily(FamilyEditViewModel val)
        {
            val.Edit.Execute(null);
            _navigationService.ShowFamilyEditor(val);
        }




        private RelayCommand<FamilyEditViewModel> _deleteFamily;
        public RelayCommand<FamilyEditViewModel> DeleteFamily
        {
            get
            {
                return _deleteFamily ?? (_deleteFamily = new RelayCommand<FamilyEditViewModel>(ExecDeleteFamily, CanDeleteFamily));
            }
        }

        /// <summary>
        /// Checks whether the DeleteFamily command is executable
        /// </summary>
        private bool CanDeleteFamily(FamilyEditViewModel val)
        {
            return val != null;
        }

        /// <summary>
        /// Executes the DeleteFamily command 
        /// </summary>
        private void ExecDeleteFamily(FamilyEditViewModel val)
        {

            base.ConfirmAction(doit =>
              {
                  if (doit)
                  {
                      base.ResetError();
                      IsBusy = true;
                      _dataService.Families.Remove(val.Entity);
                      _dataService.SubmitAsync(op =>
                          {
                              IsBusy = false;
                              if (op.HasError)
                              {
                                  base.HandleDomainError(op, "Deleting family failed.");
                              }
                              else
                              {

                              }
                          });
                  }
              }, "Delete Family");
        }



        private RelayCommand<FamilyEditViewModel> _move;
        public RelayCommand<FamilyEditViewModel> Move
        {
            get
            {
                return _move ?? (_move = new RelayCommand<FamilyEditViewModel>(ExecMoveSelectedFamily, CanMoveSelectedFamily));
            }
        }

        /// <summary>
        /// Checks whether the MoveSelectedFamily command is executable
        /// </summary>
        private bool CanMoveSelectedFamily(FamilyEditViewModel val)
        {
            return true;
        }

        /// <summary>
        /// Executes the MoveSelectedFamily command 
        /// </summary>
        private void ExecMoveSelectedFamily(FamilyEditViewModel val)
        {
            _navigationService.ShowMoveToFamily(val);
        }


        private RelayCommand<FamilyEditViewModel> _copyAsFasta;
        public RelayCommand<FamilyEditViewModel> CopyAsFasta
        {
            get
            {
                return _copyAsFasta ?? (_copyAsFasta = new RelayCommand<FamilyEditViewModel>(ExecCopyAsFasta, CanCopyAsFasta));
            }
        }

        /// <summary>
        /// Checks whether the CopyAsFasta command is executable
        /// </summary>
        private bool CanCopyAsFasta(FamilyEditViewModel val)
        {
            return true;
        }

        /// <summary>
        /// Executes the CopyAsFasta command 
        /// </summary>
        private void ExecCopyAsFasta(FamilyEditViewModel val)
        {
            string fasta = CopyAsFastaRec(val.Entity);
            Clipboard.SetText(fasta);
        }

        private string CopyAsFastaRec(FamilyDto familyDto)
        {
            FastAFormatter formatter = new FastAFormatter();
            string ret = "";
            foreach (var item in familyDto.Items.Where(x=>!string.IsNullOrEmpty(x.ProteinSequence)))
            {
                ISequence seq = new Sequence(Alphabets.AmbiguousProtein, item.ProteinSequence);
                seq.ID = item.Name;
                ret += formatter.Format(seq);
            }
            foreach (var item in familyDto.SubFamilies)
            {
                ret += CopyAsFastaRec(item);
            }
            return ret;
        }










    }
}
